<?php
// File: SwooleTcpServer.php

use Swoole\Process;
use Swoole\Server;

class SwooleServer
{
    protected $server;
    protected $config;
    protected $rootDir;

    private $events;

    public function __construct(array $config, $Events=[])
    {
        $this->config = $config;
        $this->defineConstants();
        $this->rootDir = DIR;
        $this->events = $Events;
        // 启用协程 Hook
        Swoole\Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
    }

    /**
     * 定义常量
     */
    protected function defineConstants()
    {
        defined('MASTER_PID_FILE') || define('MASTER_PID_FILE', DIR . '/runtime/' . GAME_NAME . '_' . APP_NAME . '_swoole_master.pid');
        defined('MANAGER_PID_FILE') || define('MANAGER_PID_FILE', DIR . '/runtime/' . GAME_NAME . '_' . APP_NAME . '_swoole_manager.pid');
        defined('LOG_FILE') || define('LOG_FILE', DIR . '/runtime/' . GAME_NAME . '_' . APP_NAME . '_swoole.log');
    }

    /**
     * 设置进程名称
     */
    protected function setProcessName($name)
    {
        $names = array_filter([GAME_NAME, APP_NAME, APP_ENV, 'group'.GROUP, $name,$this->config['worker_name'] ?? '']);
        swoole_set_process_name(implode('_', $names));
    }

    /**
     * 初始化 Server
     */
    public function start()
    {
        $host = $this->config['server']['host'] ?? '127.0.0.1';
        $port = $this->config['server']['port'] ?? 9501;

        $this->server= new Server($host, $port);

        $this->configureServer();
        $this->registerEvents();

        echo "Starting on {$host}:{$port}...\n";
        $this->server->start();
    }

    /**
     * 配置 参数
     */
    protected function configureServer()
    {
        $this->server->set([
            'worker_num' => WORKER_NUM,
            'enable_coroutine' => true,
            'reload_async' => true,
            'max_wait_time' => 60,
            'log_date_format' => '%Y-%m-%d %H:%M:%S',
            'display_errors' => true,
            'debug_mode' => APP_DEBUG,
            'daemonize' => APP_ENV === 'production',
            'log_file' => LOG_FILE,
        ]);
    }

    /**
     * 注册所有事件回调
     */
    protected function registerEvents()
    {
        $allEvents = ['Start','ManagerStart','ManagerStop','WorkerStart','WorkerStop','WorkerExit','Connect','Receive','Close','WorkerError'];
        foreach ($allEvents as $event){
            if(in_array($event,array_keys($this->events))) continue;
            $this->server->on($event, [$this, 'on'.$event]);
        }
    }

    public function onStart($server)
    {
        $this->setProcessName('Master');
        file_put_contents(MASTER_PID_FILE, $server->master_pid);
        echo "started. Master PID: {$server->master_pid}\n";
    }

    public function onManagerStart($server)
    {
        $this->setProcessName('Manager');
        //file_put_contents(MANAGER_PID_FILE, $server->manager_pid);
        echo "ManagerStart: PID = {$server->manager_pid}\n";
    }

    public function onManagerStop($server)
    {
        if (file_exists(MASTER_PID_FILE)) {
            $pid = (int)file_get_contents(MASTER_PID_FILE);
            if ($pid && @posix_kill($pid, 0)) {
                echo "is still running (PID: $pid)\n";
            }
            unlink(MASTER_PID_FILE);
            echo "Master PID file cleaned up.\n";
        }
        if (file_exists(MANAGER_PID_FILE)) {
            unlink(MANAGER_PID_FILE);
            echo "Manager PID file cleaned up.\n";
        }
    }

    public function onWorkerStart($server, $workerId)
    {
        $this->setProcessName('Worker_' . $workerId);
        require_once $this->rootDir . '/vendor/autoload.php';

        $baseWorker = new \Tyrone\Lib\SingleWorker();
        $baseWorker->init($server, $workerId, $this->config);
    }

    public function onWorkerStop($server, $workerId)
    {
        $this->clearTimer($server, $workerId);
    }

    public function onWorkerExit($server, $workerId)
    {
        $this->clearTimer($server, $workerId);
        echo "Worker[{$workerId}] exited.\n";
    }
    public function onWorkerError($server, $workerId, $pid, $exit_code, $signal)
    {
        $this->clearTimer($server, $workerId);
        echo "Worker[{$workerId}] Error.\n";
    }
    public function onConnect($server, $fd)
    {
        echo "Client: Connect.\n";
    }

    public function onReceive($server, $fd, $reactorId, $data)
    {
        require_once $this->rootDir . '/vendor/autoload.php';
        $internalHandler = new \Tyrone\Lib\InternalHandler();
        $internalHandler->Receive($server, $fd, $reactorId, $data, $this->config);
    }

    public function onClose($server, $fd)
    {
        echo "Client: Close.\n";
    }

    /**
     * 清理 Worker 定时器
     */
    protected function clearTimer($server, $workerId)
    {
        $ticks = $server->ticks[$workerId] ?? [];
        if (!is_array($ticks)) {
            $ticks = [$ticks];
        }
        foreach ($ticks as $timerId) {
            if ($timerId) {
                $server->clearTimer($timerId);
            }
        }
    }


    /**
     * 获取 实例（用于外部操作）
     */
    public function getServer()
    {
        return $this->server;
    }
}